﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp;
using Abp.Application.Services.Dto;
using Abp.Auditing;
using Abp.Authorization;
using Abp.Configuration;
using Abp.Notifications;
using Abp.Runtime.Session;
using Abp.UI;
using Sunlit.House.Notifications.Dto;
using Sunlit.House.Authorization.Users;
using Abp.Domain.Repositories;

namespace Sunlit.House.Notifications
{
    [AbpAuthorize]
    public class NotificationAppService : HouseAppServiceBase, INotificationAppService
    {
        private readonly INotificationDefinitionManager _notificationDefinitionManager;
        private readonly IUserNotificationManager _userNotificationManager;
        private readonly INotificationSubscriptionManager _notificationSubscriptionManager;
        private readonly INotificationPublisher _notificationPublisher;
        private readonly IRepository<User, long> _userRepository;

        public NotificationAppService(
            INotificationDefinitionManager notificationDefinitionManager,
            IUserNotificationManager userNotificationManager,
            INotificationSubscriptionManager notificationSubscriptionManager,
            INotificationPublisher notificationPublisher,
            IRepository<User, long> userRepository)
        {
            _notificationDefinitionManager = notificationDefinitionManager;
            _userNotificationManager = userNotificationManager;
            _notificationSubscriptionManager = notificationSubscriptionManager;
            _notificationPublisher = notificationPublisher;
            _userRepository = userRepository;
        }
        /// <summary>
        /// 获取用户的通知消息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [DisableAuditing]
        public async Task<GetNotificationsOutput> GetUserNotifications(GetUserNotificationsInput input)
        {
            var totalCount = await _userNotificationManager.GetUserNotificationCountAsync(
                AbpSession.ToUserIdentifier(), input.State, input.StartDate, input.EndDate
                );

            var unreadCount = await _userNotificationManager.GetUserNotificationCountAsync(
                AbpSession.ToUserIdentifier(), UserNotificationState.Unread, input.StartDate, input.EndDate
                );
            var notifications = await _userNotificationManager.GetUserNotificationsAsync(
                AbpSession.ToUserIdentifier(), input.State, input.SkipCount, input.MaxResultCount, input.StartDate, input.EndDate
                );

            return new GetNotificationsOutput(totalCount, unreadCount, notifications);
        }
        public async Task<UserNotification> GetUserFirstNotification(long? userId)
        {
            UserIdentifier user = null;
            if (userId.HasValue)
            {
                user = new UserIdentifier(AbpSession.TenantId, userId.Value);
            } else
            {
                user = AbpSession.ToUserIdentifier();
            }
            var notifications = await _userNotificationManager.GetUserNotificationsAsync(
                user, UserNotificationState.Unread);

            return notifications.FirstOrDefault();

            //var data =  notifications.FirstOrDefault()?.Notification.Data;
            //if (data == null)
            //{
            //    return null;
            //} else
            //{
            //    return data as CommonMessageNotificationData;
            //}
        }
        /// <summary>
        /// 将所有消息设为已读
        /// </summary>
        /// <returns></returns>
        public async Task SetAllNotificationsAsRead()
        {
            await _userNotificationManager.UpdateAllUserNotificationStatesAsync(AbpSession.ToUserIdentifier(), UserNotificationState.Read);
        }
        /// <summary>
        /// 将消息设为已读
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task SetNotificationAsRead(EntityDto<Guid> input)
        {
            var userNotification = await _userNotificationManager.GetUserNotificationAsync(AbpSession.TenantId, input.Id);
            if (userNotification == null)
            {
                return;
            }

            if (userNotification.UserId != AbpSession.GetUserId())
            {
                throw new Exception(string.Format("Given user notification id ({0}) is not belong to the current user ({1})", input.Id, AbpSession.GetUserId()));
            }

            await _userNotificationManager.UpdateUserNotificationStateAsync(AbpSession.TenantId, input.Id, UserNotificationState.Read);
        }
        /// <summary>
        /// 获取消息设置
        /// </summary>
        /// <returns></returns>
        public async Task<GetNotificationSettingsOutput> GetNotificationSettings()
        {
            var output = new GetNotificationSettingsOutput();

            output.ReceiveNotifications = await SettingManager.GetSettingValueAsync<bool>(NotificationSettingNames.ReceiveNotifications);

            //Get general notifications, not entity related notifications.
            var notificationDefinitions = (await _notificationDefinitionManager.GetAllAvailableAsync(AbpSession.ToUserIdentifier())).Where(nd => nd.EntityType == null);

            output.Notifications = ObjectMapper.Map<List<NotificationSubscriptionWithDisplayNameDto>>(notificationDefinitions);

            var subscribedNotifications = (await _notificationSubscriptionManager
                .GetSubscribedNotificationsAsync(AbpSession.ToUserIdentifier()))
                .Select(ns => ns.NotificationName)
                .ToList();

            output.Notifications.ForEach(n => n.IsSubscribed = subscribedNotifications.Contains(n.Name));

            return output;
        }
        /// <summary>
        /// 更新消息设置
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UpdateNotificationSettings(UpdateNotificationSettingsInput input)
        {
            await SettingManager.ChangeSettingForUserAsync(AbpSession.ToUserIdentifier(), NotificationSettingNames.ReceiveNotifications, input.ReceiveNotifications.ToString());

            foreach (var notification in input.Notifications)
            {
                if (notification.IsSubscribed)
                {
                    await _notificationSubscriptionManager.SubscribeAsync(AbpSession.ToUserIdentifier(), notification.Name);
                }
                else
                {
                    await _notificationSubscriptionManager.UnsubscribeAsync(AbpSession.ToUserIdentifier(), notification.Name);
                }
            }
        }
        /// <summary>
        /// 删除通知消息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task DeleteNotification(EntityDto<Guid> input)
        {
            var notification = await _userNotificationManager.GetUserNotificationAsync(AbpSession.TenantId, input.Id);
            if (notification == null)
            {
                return;
            }

            if (notification.UserId != AbpSession.GetUserId())
            {
                throw new UserFriendlyException("你不是本通知消息的拥有者");
            }

            await _userNotificationManager.DeleteUserNotificationAsync(AbpSession.TenantId, input.Id);
        }
        /// <summary>
        /// 删除所有通知消息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task DeleteAllUserNotifications(DeleteAllUserNotificationsInput input)
        {
            await _userNotificationManager.DeleteAllUserNotificationsAsync(
                AbpSession.ToUserIdentifier(),
                input.State,
                input.StartDate,
                input.EndDate);
        }
        public async Task SendCommonMessageToUser(SendCommonMessageToUserInput input)
        {
            UserIdentifier user = new UserIdentifier(AbpSession.TenantId, input.UserId);
            await _notificationPublisher.PublishAsync("CommonMessage", new CommonMessageNotificationData(input.Title,input.Msg), userIds:new[] { user });
        }
        public async Task SendCommonMessageToAllUser(SendCommonMessageToUserInput input)
        {
            var list = await _userRepository.GetAllListAsync();
            var userIds = list.Select(u => new UserIdentifier(AbpSession.TenantId, u.Id));
            await _notificationPublisher.PublishAsync("CommonMessage", new CommonMessageNotificationData(input.Title,input.Msg),userIds:userIds.ToArray());
        }
    }
}